package com.jmyd.commons.redis.repository;

import org.springframework.data.redis.core.*;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Created by samphin on 2017/10/24.
 *
 * @param <T>
 */
public abstract class BaseRedisRepositoryImpl<T> implements BaseRedisRepository<T> {

    @Resource
    public RedisTemplate<String, T> redisTemplate;

    /**
     * 获取自增索引
     *
     * @param key .
     * @return .
     */
    @Override
    public Long incrementAndGet(String key) {
        RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
        return entityIdCounter.incrementAndGet();
    }

    @Override
    public void save(String key, T t) {
        getOpsForValue().set(key, t);
    }

    @Override
    public void save(String key, T t, Date expireDate) {
        save(key, t);
        redisTemplate.expireAt(key, expireDate);
    }

    @Override
    public void save(String key, T t, long expireTime, TimeUnit unit) {
        save(key, t);
        redisTemplate.expire(key, expireTime, unit);
    }

    @Override
    public void save(String key, T t, Duration duration){
        save(key,t);
        redisTemplate.expire(key,duration.getSeconds(),TimeUnit.SECONDS);
    }


    @Override
    public T get(String key) {
        return getOpsForValue().get(key);
    }

    @Override
    public boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    @Override
    public void saveAsList(final String key, List<T> list, long expireTime, TimeUnit timeUnit) {
        if (!CollectionUtils.isEmpty(list)) {
            redisTemplate.delete(key);
            getOpsForList().leftPushAll(key, list);
            redisTemplate.expire(key, expireTime, timeUnit);
        }
    }

    @Override
    public Long saveAsList(final String key, List<T> list) {
        return getOpsForList().leftPushAll(key, list);
    }

    @Override
    public void rightPush(String key, T value) {
        getOpsForList().rightPush(key, value);
    }

    @Override
    public void leftPop(String key) {
        getOpsForList().leftPop(key);
    }

    @Override
    public void delete(String key) {
        redisTemplate.delete(key);
    }

    @Override
    public void delete(Collection key) {
        redisTemplate.delete(key);
    }

    @Override
    public void remove(final String key, long num, T t) {
        getOpsForList().remove(key, num, t);
    }

    @Override
    public void saveAsHash(final String key, final String hashKey, T t) {
        getOpsForHash().delete(key, hashKey);
        getOpsForHash().put(key, hashKey, t);
    }

    @Override
    public void saveAsHash(final String key, final String hashKey, T t, long timeout, TimeUnit unit) {
        getOpsForHash().delete(key, hashKey);
        getOpsForHash().put(key, hashKey, t);
        redisTemplate.expire(key, timeout, unit);
    }

    @Override
    public List<T> getList(final String key, Long start, Long end) {
        if (null == start) {
            start = 0L;
        }
        if (null == end) {
            end = -1L;
        }
        List<T> result = getOpsForList().range(key, start, end);
        return result;
    }

    @Override
    public T getObject(final String key, final String hashKey) {
        return getOpsForHash().get(key, hashKey);
    }

    @Override
    public Map<String, T> hGetAll(String key) {
        return getOpsForHash().entries(key);
    }

    protected ListOperations<String, T> getOpsForList() {
        return redisTemplate.opsForList();
    }

    protected SetOperations<String, T> getOpsForSet() {
        return redisTemplate.opsForSet();
    }

    protected ValueOperations<String, T> getOpsForValue() {
        return redisTemplate.opsForValue();
    }

    protected HashOperations<String, String, T> getOpsForHash() {
        return redisTemplate.opsForHash();
    }

}
